package org.moonshot.cvm;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class CVMClassSpec extends CVMClass
{
	private final String name;
	private final String superclass;
	private final String[] memberNames;
	private final String[] sharedNames;
	private final Object[] constants;
	
	private final Map<String, CVMMethod> newMethods = new HashMap<String, CVMMethod> ();
	private final Map<String, CVMMethod> instanceMethods = new HashMap<String, CVMMethod> ();
	private final Map<String, CVMMethod> classMethods = new HashMap<String, CVMMethod> ();
	
	public CVMClassSpec(File aFile)
		throws IOException
	{
		final BufferedInputStream theStream = new BufferedInputStream (new FileInputStream (aFile));
		final CVMBinaryIO io = new CVMBinaryIO ();
		
		name = io.pullString(theStream);
		superclass = io.pullString(theStream);
		memberNames = io.pullArray(theStream);
		sharedNames = io.pullArray(theStream);
		constants = io.pullArray(theStream);
		
		final int methodCount = io.pullInt(theStream);
		for(int i = 0; i < methodCount; i++)
		{
			final CVMMethod theMethod = io.pullMethod(theStream);
			switch(theMethod.scope)
			{
			case CLASS:
				classMethods.put (theMethod.name, theMethod);
				break;
				
			case CONSTRUCTOR:
				newMethods.put (theMethod.name, theMethod);
				break;
			
			case INSTANCE:
				instanceMethods.put (theMethod.name, theMethod);
				break;
			}
		}
		
	}
	
	public Object callInstance (ChattyVM aVM, Object aInstance, String aMethod, ChattyStack aStack, int nParams)
		throws CVMRuntimeException, CVMBlockReturnException
	{
		CVMMethod theMethod = classMethods.get (aMethod);
		if( theMethod == null ) theMethod = instanceMethods.get (aMethod);
		if( theMethod == null ) theMethod = newMethods.get (aMethod);
		
		if( theMethod == null )
			return getSuperclass (aVM).callInstance (aVM, aInstance, aMethod, aStack, nParams);
		
		return aVM.execute(aInstance, theMethod, aStack);
	}
	
	public I_ChattyClass getSuperclass (ChattyVM aVM)
	{
		return aVM.classNamed (superclass);
	}
	
	public String getName ()
    {
	    return name;
    }
	
	public String[] getMemberNames ()
    {
	    return memberNames;
    }
	
	public String[] getSharedNames ()
    {
	    return sharedNames;
    }
	
	public Object[] getConstants ()
    {
	    return constants;
    }
	
	public Map<String, CVMMethod> getClassMethods ()
    {
	    return new TreeMap<String, CVMMethod> (classMethods);
    }
	
	public Map<String, CVMMethod> getInstanceMethods ()
    {
	    return new TreeMap<String, CVMMethod> (instanceMethods);
    }
	
	public Map<String, CVMMethod> getNewMethods ()
	{
		return new TreeMap<String, CVMMethod> (newMethods);
	}
}
